package edu.gatech.spacetraderteam3.view;

import java.awt.Color;
import java.awt.Graphics2D;
import java.util.HashMap;
import java.util.Map;

import edu.gatech.spacetraderteam3.controller.GUIEventHandler;
import edu.gatech.spacetraderteam3.debug.Debug;
import edu.gatech.spacetraderteam3.model.GameState;
import edu.gatech.spacetraderteam3.model.Resource;

/**
 * Represents the buy/sell dialogs that may be used in
 * any instance of the game
 * @author Alexander Ikonomidis and Ashutosh Gupta
 * @version 1.0
 */
public class ViewBuySellOverlay extends View {

    /**
     * The planet's list of products for sale
     */
    private Map<Resource, Integer> buyableProducts;

    /**
     * The list of products a player can sell to a planet
     */
    private Map<Resource, Integer> sellableProducts;

    /**
     * The weight of the items in the inventory
     */
    private Map<Resource, Integer> itemWeights;

    /**
     * The inventory of the player
     */
    private Map<Resource, Integer> playerAmount;

    /**
     * indicates whether the overlay is enabled or not
     */
    private boolean enabled = false;

    /**
     * The buy and sell panel located on the lower right hand corner
     */
    private final SGGWindow buySellPanel;

    // Buy Dialog Components
    /**
     * The window that allows the player to buy goods
     */
    private SGGWindow buyDialog;

    /**
     * The button to complete a trade transaction
     */
    private SGGButton buyButton;

    /**
     * Spins to dictate the amount wished to purchase
     */
    private SGGSpinner buyQuantitySpinner;

    /**
     * The total price of the goods that wished to be purchased
     */
    private SGGLabel buyTotalLabel;

    /**
     * The price of a single item
     */
    private final SGGLabel buyItemPrice;

    /**
     * The drop down box to choose something to buy
     */
    private SGGDropDownBox<Resource> buyDropDown;

    // Sell Dialog Components
    /**
     * The sell dialog box that allows the user to sell goods
     */
    private SGGWindow sellDialog;

    /**
     * The button used to complete a sell transaction
     */
    private SGGButton sellButton;

    /**
     * The amount a user wishes to sell of a particular good
     */
    private SGGSpinner sellQuantitySpinner;

    /**
     * The total cash back for selling x amount of goods
     */
    private SGGLabel sellTotalLabel;

    /**
     * The sell price for an individual item
     */
    private final SGGLabel sellItemPrice;

    /**
     * A drop down box with the resources available for selling
     */
    private SGGDropDownBox<Resource> sellDropDown;

    // Shared by both buy/sell Dialogs
    /**
     * Shows how much cash a player has
     */
    private final SGGLabel yourCashLabel;

    /**
     * Shows how much of item x is in your inventory
     */
    private final SGGLabel inInventoryLabel;

    /**
     * Shows the cargo's weight
     */
    private final SGGLabel cargoWeightLabel;

    /**
     * Shows item x's weight
     */
    private final SGGLabel itemWeightLabel;

    /**
     * Exits a trade
     */
    private SGGButton leaveTradeButton;

    /**
     * Integer constants for GUI placement
     */
    private final int twoButtonWidth = 260, threeButtonWidth = 361, height = 130;

    /**
     * Adds a buysell overlay to the current view
     */
    public ViewBuySellOverlay() {
        yourCashLabel = new SGGLabel("Your Money: $0");
        inInventoryLabel = new SGGLabel("In Inventory: 0");
        cargoWeightLabel = new SGGLabel("Cargo Weight:  0 / 1000 lbs");
        itemWeightLabel = new SGGLabel("Item Weight: ");
        buyItemPrice = new SGGLabel("Placeholder text");
        sellItemPrice = new SGGLabel("Placeholder text");

        buySellPanel = buildBuySellPanel();
    }

    /**
     * @return a newly built buy / sell panel
     */
    public SGGWindow buildBuySellPanel() {
        final SGGWindow window = new SGGWindow(0, 0, threeButtonWidth, 130,
                GameState.PLANET);
        window.hasPoint(false);
        window.setAlignment(SGGWindow.Alignment.BOTTOM_RIGHT);
        SGGButton button = new SGGButton("BUY");
        button.setSGGEventListener(new SGGEventListener() {
            public void doEvent(SGGEvent sgge) {
                buyQuantitySpinner.setValue(0);
                refreshBuyLabels();
                successfulTrade();
                togglePopup(buyDialog);
            }
        });
        window.add(button, 35, 42);

        button = new SGGButton("SELL");
        button.setSGGEventListener(new SGGEventListener() {
            public void doEvent(SGGEvent sgge) {
                sellQuantitySpinner.setValue(0);
                refreshSellLabels();
                successfulTrade();
                togglePopup(sellDialog);
            }
        });
        window.add(button, 136, 42);

        leaveTradeButton = new SGGButton("Done");
        leaveTradeButton.setSGGEventListener(new SGGEventListener() {
            public void doEvent(SGGEvent sgge) {
                GUIEventHandler.noTrade();
            }
        });
        window.add(leaveTradeButton, 237, 42);
        return window;
    }

    /**
     * @return a newly built buy dialog
     */
    public SGGWindow buildBuyDialog() {
        buyTotalLabel = new SGGLabel("Total Price: $0");
        buyQuantitySpinner = new SGGSpinner(0, 999, 0);
        buyQuantitySpinner.setSGGEventListener(new SGGEventListener() {
            public void doEvent(SGGEvent sgge) {
                refreshBuyLabels();
            }
        });

        buyDropDown = new SGGDropDownBox<Resource>(buyableProducts.keySet()
                .toArray(new Resource[] {}), 0);
        buyDropDown.setSGGEventListener(new SGGEventListener() {
            public void doEvent(SGGEvent sgge) {
                buyQuantitySpinner.setValue(0);
                refreshBuyLabels();
            }
        });

        buyButton = new SGGButton("BUY");
        buyButton.setSGGEventListener(new SGGEventListener() {
            public void doEvent(SGGEvent sgge) {
                successfulTrade();
                GUIEventHandler.buy(buyDropDown.getValue(), buyQuantitySpinner.getValue());
                refreshBuyLabels();
            }
        });
        refreshBuyLabels();
        final SGGWindow window = new SGGWindow(0, -100, 330, 250, GameState.PLANET);
        window.setAlignment(SGGWindow.Alignment.CENTER);
        window.setVisible(false);
        window.add(new SGGLabel("Please, do check out our merchandise:"), 30, 30);
        window.add(new SGGLabel("Quantity"), 62, 55);
        window.add(new SGGLabel("Item"), 210, 55);
        window.add(itemWeightLabel, 30, 126);
        window.add(buyQuantitySpinner, 30, 70);
        window.add(buyDropDown, 175, 70);
        window.add(buyButton, 180, 135);
        window.add(buyTotalLabel, 30, 107);
        window.add(yourCashLabel, 30, 147);
        window.add(buyItemPrice, 160, 107);
        window.add(inInventoryLabel, 30, 167);
        window.add(cargoWeightLabel, 30, 187);
        return window;
    }

    /**
     * @return a newly built sell dialog
     */
    public SGGWindow buildSellDialog() {
        sellTotalLabel = new SGGLabel("Total Price: $0");
        sellQuantitySpinner = new SGGSpinner(0, 999, 0);
        sellQuantitySpinner.setSGGEventListener(new SGGEventListener() {
            public void doEvent(SGGEvent sgge) {
                refreshSellLabels();
            }
        });

        sellDropDown = new SGGDropDownBox<Resource>(sellableProducts.keySet()
                .toArray(new Resource[] {}), 0);
        sellDropDown.setSGGEventListener(new SGGEventListener() {
            public void doEvent(SGGEvent sgge) {
                sellQuantitySpinner.setValue(0);
                sellTotalLabel.setText("Total Price:    $0");
            }
        });

        sellButton = new SGGButton("SELL");
        sellButton.setSGGEventListener(new SGGEventListener() {
            public void doEvent(SGGEvent sgge) {
                successfulTrade();
                GUIEventHandler.sell(sellDropDown.getValue(),
                                     sellQuantitySpinner.getValue());
                refreshSellLabels();
            }
        });
        refreshSellLabels();
        final SGGWindow window = new SGGWindow(0, -100, 330, 250, GameState.PLANET);
        window.setAlignment(SGGWindow.Alignment.CENTER);
        window.setVisible(false);
        window.add(new SGGLabel("Let's see what you have to offer:"), 30, 30);
        window.add(new SGGLabel("Quantity"), 62, 55);
        window.add(new SGGLabel("Item"), 210, 55);
        window.add(itemWeightLabel, 30, 126);
        window.add(sellQuantitySpinner, 30, 70);
        window.add(sellDropDown, 175, 70);
        window.add(sellButton, 180, 135);
        window.add(sellTotalLabel, 30, 107);
        window.add(yourCashLabel, 30, 147);
        window.add(sellItemPrice, 160, 107);
        window.add(inInventoryLabel, 30, 167);
        window.add(cargoWeightLabel, 30, 187);
        return window;
    }

    /**
     * Refreshes the labels on the buy dialog
     */
    public void refreshBuyLabels() {
        final int total = buyableProducts.get(buyDropDown.getValue())
                * buyQuantitySpinner.getValue();
        buyTotalLabel.setText("Total Price: $" + total);
        if (playerAmount != null) {
            inInventoryLabel.setText("In inventory: "
                    + playerAmount.get(buyDropDown.getValue()));
        }
        if (buyableProducts != null) {
            buyItemPrice.setText("Price of Item: $"
                    + buyableProducts.get(buyDropDown.getValue()));
        }
        if (itemWeights != null) {
            itemWeightLabel.setText("Item Weight: "
                    + itemWeights.get(buyDropDown.getValue()));
        }
    }

    /**
     * Refreshes the labels on the sell dialog
     */
    public void refreshSellLabels() {
        final int total = sellableProducts.get(sellDropDown.getValue())
                * sellQuantitySpinner.getValue();
        sellTotalLabel.setText("Total Price:    $" + total);
        if (playerAmount != null) {
            inInventoryLabel.setText("In inventory: "
                    + playerAmount.get(sellDropDown.getValue()));
        }
        if (sellableProducts != null) {
            sellItemPrice.setText("Price of Item: $"
                    + sellableProducts.get(sellDropDown.getValue()));
        }
        if (itemWeights != null) {
            itemWeightLabel.setText("Item Weight: "
                    + itemWeights.get(sellDropDown.getValue()));
        }
    }

    /**
     * Sets the colors of the labels to the conditions of a successful trade
     */
    public void successfulTrade() {
        cargoWeightLabel.setColor(Color.BLACK);
        yourCashLabel.setColor(Color.BLACK);
        inInventoryLabel.setColor(Color.BLACK);
    }

    /**
     * Sets the cash label to red if the player doesn't have enough money
     */
    public void notEnoughMoney() {
        yourCashLabel.setColor(Color.RED);
    }

    /**
     * Sets the cargo label to red if the player doesn't have enough space
     */
    public void notEnoughCargoSpace() {
        cargoWeightLabel.setColor(Color.RED);
    }

    /**
     * Sets the inventory label to red to indicate an item is not in the inventory
     */
    public void notEnoughItemToSell() {
        inInventoryLabel.setColor(Color.RED);
    }

    /**
     * paints the current buysell overlay
     * @param g2 graphics object
     */
    public void paint(Graphics2D g2) {
        buySellPanel.paint(g2);
        buyDialog.paint(g2);
        sellDialog.paint(g2);
    }

    /**
     * Initializes the information held by the buy sell overaly
     * @param pricesAndWeights
     * @param cargoWeight
     */
    public void initialize(Map<Resource, int[]> pricesAndWeights, int cargoWeight) { // buyPrice,
                                                                                     // sellPrice,
                                                                                     // weight
        buyableProducts = new HashMap<Resource, Integer>();
        sellableProducts = new HashMap<Resource, Integer>();
        itemWeights = new HashMap<Resource, Integer>();
        this.cargoWeightLabel.setText("Cargo Weight:    " + cargoWeight + " / 1000 lbs");
        for (Resource r : pricesAndWeights.keySet()) {
            if (pricesAndWeights.get(r)[0] != -1) {
                buyableProducts.put(r, pricesAndWeights.get(r)[0]);
            }
            sellableProducts.put(r, pricesAndWeights.get(r)[1]);
            itemWeights.put(r, pricesAndWeights.get(r)[2]);
            Debug.write("BuyPrice of " + r + ": " + buyableProducts.get(r) + "\n"
                    + "SellPrice of " + r + ": " + sellableProducts.get(r), 2);
        }
        if (buyDialog != null) {
            buyDialog.dispose();
        }
        if (sellDialog != null) {
            sellDialog.dispose();
        }
        PopupWindows.remove(buyDialog);
        PopupWindows.remove(sellDialog);
        buyDialog = buildBuyDialog();
        sellDialog = buildSellDialog();
        PopupWindows.add(buyDialog);
        PopupWindows.add(sellDialog);

        hidePopups();
    }

    /**
     * sets the player's inventory
     * @param map
     */
    public void setPlayerAmount(Map<Resource, Integer> map) {
        this.playerAmount = map;
    }

    /**
     * Sets the player's cargo weight
     * @param maxWeight
     * @param currWeight
     */
    public void setWeight(int maxWeight, int currWeight) {
        cargoWeightLabel.setText("Cargo Weight: " + currWeight + " / " + maxWeight
                + " lbs");
    }

    /**
     * Sets the current credits held by the player
     * @param credits
     */
    public void setCredits(int credits) {
        yourCashLabel.setText("Your money: $" + credits);
    }

    /**
     * Enables the overaly to be visible
     * @param enabled
     */
    public void enableOverlay(boolean enabled) {
        this.enabled = enabled;
        buyDialog.setVisible(enabled);
        sellDialog.setVisible(enabled);
        buySellPanel.setVisible(enabled);
    }

    /**
     * sets the overlay into listening mode for mouse clicks and other events
     * @param gameState
     */
    public void setListeningMode(GameState gameState) {
        buyDialog.setListeningMode(gameState);
        sellDialog.setListeningMode(gameState);
        buySellPanel.setListeningMode(gameState);
    }
    
    /**
     * Checks if this buy sell overlay is enabled
     * @return the true or false value
     */
    public boolean isEnabled() {
        return enabled;
    }

    /**
     * Shows the leave button if true is passed in
     * @param showLeaveButton
     */
    public void showLeaveButton(boolean showLeaveButton) {
        buySellPanel.setDimensions(showLeaveButton ? threeButtonWidth : twoButtonWidth,
                                   height);
        leaveTradeButton.setVisible(showLeaveButton);
    }

    /**
     * @return This the buy/sell overlay.
     */
    public String toString() {
        return "This the buy/sell overlay.";
    }
}
